package cc.siyecao.mapper.conditions;

import cc.siyecao.mapper.Criteria;
import cc.siyecao.mapper.enums.SqlKeyword;
import cc.siyecao.mapper.enums.SqlLike;
import cc.siyecao.mapper.provider.entity.EntityColumn;
import cc.siyecao.mapper.wrapper.IWrapper;

import java.util.Arrays;
import java.util.List;

import static java.util.stream.Collectors.joining;

public interface Condition<W, R> extends StringCondition<W> {
    /**
     * 普通查询条件
     *
     * @param condition 是否执行
     * @param applySql  条件sql
     */

    default W addCondition(boolean condition, String applySql) {
        return maybeDo( condition, () -> getCriteria().addCriterion( applySql ) );
    }

    /**
     * 普通查询条件
     *
     * @param condition 是否执行
     * @param applySql  条件sql
     */

    default W addCondition(boolean condition, String applySql, Object value) {
        return maybeDo( condition, () -> getCriteria().addCriterion( applySql, value ) );
    }

    /**
     * 普通查询条件
     *
     * @param condition  是否执行
     * @param column     属性
     * @param sqlKeyword SQL 关键词
     */

    default W addCondition(boolean condition, R column, SqlKeyword sqlKeyword) {
        return maybeDo( condition, () -> getCriteria().addCriterion( columnName( column ), sqlKeyword ) );
    }

    /**
     * 普通查询条件
     *
     * @param condition  是否执行
     * @param column     属性
     * @param sqlKeyword SQL 关键词
     */

    default W addCondition(boolean condition, EntityColumn column, SqlKeyword sqlKeyword) {
        return maybeDo( condition, () -> getCriteria().addCriterion( column.column(), sqlKeyword ) );
    }

    /**
     * BETWEEN查询条件
     *
     * @param condition  是否执行
     * @param column     属性
     * @param sqlKeyword SQL 关键词
     * @param val1       条件值1
     * @param val2       条件值2
     */

    default W addCondition(boolean condition, R column, SqlKeyword sqlKeyword, Object val1, Object val2) {
        return maybeDo( condition, () -> getCriteria().addCriterion( columnName( column ), sqlKeyword, val1, val2 ) );
    }

    /**
     * 普通查询条件
     *
     * @param condition  是否执行
     * @param column     属性
     * @param sqlKeyword SQL 关键词
     * @param val        条件值
     */

    default W addCondition(boolean condition, R column, SqlKeyword sqlKeyword, Object val, SqlLike sqlLike) {
        return maybeDo( condition, () -> getCriteria().addCriterion( columnName( column ), sqlKeyword, likeValue( val, sqlLike ) ) );
    }

    /**
     * 普通查询条件
     *
     * @param condition  是否执行
     * @param column     属性
     * @param sqlKeyword SQL 关键词
     * @param values     条件值
     */

    default W addCondition(boolean condition, R column, SqlKeyword sqlKeyword, Object... values) {
        return addCondition( condition, column, sqlKeyword, Arrays.asList( values ) );
    }

    /**
     * 普通查询条件
     *
     * @param condition  是否执行
     * @param column     属性
     * @param sqlKeyword SQL 关键词
     * @param val        条件值
     */

    default W addCondition(boolean condition, EntityColumn column, SqlKeyword sqlKeyword, Object val) {
        return maybeDo( condition, () -> getCriteria().addCriterion( column.column(), sqlKeyword, val ) );
    }

    /**
     * 普通查询条件
     *
     * @param condition  是否执行
     * @param column     属性
     * @param sqlKeyword SQL 关键词
     * @param val        条件值
     */

    default W addCondition(boolean condition, R column, SqlKeyword sqlKeyword, Object val) {
        return maybeDo( condition, () -> getCriteria().addCriterion( columnName( column ), sqlKeyword, val ) );
    }

    default String likeValue(Object str, SqlLike type) {
        switch (type) {
            case LEFT:
                return PERCENT + str;
            case RIGHT:
                return str + PERCENT;
            default:
                return PERCENT + str + PERCENT;
        }
    }

    /**
     * 获取 columnName
     */
    String columnName(R column);

    /**
     * 获取 fieldName
     */
    String fieldName(R column);

    Criteria getCriteria();

}
